package com.newsee.remote.ecommerce.commerce.colipu.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.newsee.remote.common.database.entity.CommerceColipuSkuDetail;
import com.newsee.remote.common.database.mapper.CommerceColipuSkuDetailMapper;
import com.newsee.remote.common.dto.ecommerce.colipu.CheckUpdateSkuCol;
import com.newsee.remote.common.dto.ecommerce.colipu.SkuDetailColDTO;
import com.newsee.remote.common.dto.ecommerce.colipu.SkuPriceColDTO;
import com.newsee.remote.common.enumeration.DeleteFlagEnum;
import com.newsee.remote.common.enumeration.EcommerceEnum;
import com.newsee.remote.common.utils.ecache.ConcurrentHashMapCacheUtil;
import com.newsee.remote.common.utils.http.HttpClientExecutor;
import com.newsee.remote.common.utils.tools.CcUtils;
import com.newsee.remote.ecommerce.commerce.colipu.service.IColipuSkuDetailService;
import com.newsee.remote.ecommerce.commerce.colipu.service.IColipuTokenService;
import com.newsee.remote.ecommerce.service.IShMaterialService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.Future;

/**
 * <p>
 * 科力普商品详情服务实现类
 * </p>
 *
 * @author liangzhichen
 * @since 2019-07-16
 */
@Slf4j
@Service
public class ColipuSkuDetailServiceImpl extends ServiceImpl<CommerceColipuSkuDetailMapper, CommerceColipuSkuDetail> implements IColipuSkuDetailService {

    /**
     * 获取分类下skuId方法url
     */
    @Value("${colipuGetSkuIdUrl}")
    private String colipuGetSkuIdUrl;

    /**
     * 统一url
     */
    @Value("${colipuContextPath}")
    private String colipuContextPath;

    /**
     * 获取商品基本信息方法名
     */
    @Value("${colipuGetSkuDetailUrl}")
    private String colipuGetSkuDetailUrl;

    /**
     * 获取商品价格方法名
     */
    @Value("${colipuGetSkuPriceUrl}")
    private String colipuGetSkuPriceUrl;

    /**
     * 默认配置的线程池
     */
    @Resource(name = "defaultThreadPool")
    private ThreadPoolTaskExecutor executor;

    /**
     * 分批次同步商品，每次200
     */
    private final static int SIZE = 200;

    private final IColipuTokenService iColipuTokenService;

    private final IShMaterialService iShMaterialService;

    public ColipuSkuDetailServiceImpl(IColipuTokenService iColipuTokenService, IShMaterialService iShMaterialService) {
        this.iColipuTokenService = iColipuTokenService;
        this.iShMaterialService = iShMaterialService;
    }

    @Override
    public void sync(List<String> categoryIds) {
        List<Future> futures = new ArrayList<>();

        for (String categoryId : categoryIds) {
            Future<?> future = executor.submit(() -> syncSkuIdsByCategoryId(categoryId));
            futures.add(future);
        }

        for (Future future : futures) {
            while (true) {
                if (future.isDone() && !future.isCancelled()) {
                    try {
                        future.get();
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error("同步分类下商品业务异常:" + e.getMessage());
                    }
                    break;
                } else {
                    //每次轮询休息30毫秒（CPU纳秒级），避免CPU高速轮循耗空CPU
                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        log.error("同步分类下商品异常:" + e.getMessage());
                    }
                }
            }
        }

        log.info("商品同步中间表:" + LocalTime.now() + "完成");
        //释放锁
        ConcurrentHashMapCacheUtil.remove(EcommerceEnum.E_COLIPU.getDesc() + "sync");

        //同步到中间表
        syncColopuMaterial();
    }

    /**
     * 开始同步中间表的数据
     */
    private void syncColopuMaterial() {
        //默认获取第一页的数据
        IPage<CommerceColipuSkuDetail> result = getPage(1, SIZE);
        //总页数
        long pages = result.getPages();

        //需要往中间添加关联主键的数据
        List<CommerceColipuSkuDetail> addSkus;
        addSkus = iShMaterialService.syncSystem(result.getRecords());
        if (CollectionUtils.isNotEmpty(addSkus)) {
            addSkus.forEach(this::updateById);
        }
        //如果不只一页
        if (pages > 1) {
            for (int i = 2; i <= pages; i++) {
                result = getPage(i, SIZE);
                addSkus = iShMaterialService.syncSystem(result.getRecords());
                if (CollectionUtils.isNotEmpty(addSkus)) {
                    addSkus.forEach(this::updateById);
                }
            }
        }
        log.info("商品同步物料表:" + LocalTime.now() + "完成");
    }

    /**
     * 分类查询
     *
     * @param page 当前页
     * @param size 分页大小
     * @return 分页结果集
     */
    @Override
    public IPage<CommerceColipuSkuDetail> getPage(int page, int size) {
        QueryWrapper<CommerceColipuSkuDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("DeleteFlag", DeleteFlagEnum.NOT_DELETE.getCode()).orderByAsc("ID");
        Page<CommerceColipuSkuDetail> iPage = new Page<>(page, size);
        return page(iPage, queryWrapper);
    }

    /**
     * 根据分类Id同步分类下的SkuID
     *
     * @param categoryId 分类Id
     */
    private void syncSkuIdsByCategoryId(String categoryId) {
        List<String> skuIds = new ArrayList<>();

        String url = colipuContextPath + colipuGetSkuIdUrl;
        String replaceUrl = url.replace("{id}", categoryId);
        Map<String, String> params = new HashMap<>(0);
        Map<String, String> headers = new HashMap<>(1);
        headers.put("Colipu-Token", iColipuTokenService.getToken());

        try {
            String response = HttpClientExecutor.doGet(replaceUrl, params, headers);
            JSONObject jsonReturn = JSON.parseObject(response);
            if (jsonReturn.getBoolean("success")) {
                String result = jsonReturn.getString("result");
                skuIds = JSONObject.parseArray(result, String.class);
            } else {
                log.error("error:requestId(" + jsonReturn.getString("requestId")
                        + ");errorcode(" + jsonReturn.getString("errorcode")
                        + ");errormsg(" + jsonReturn.getString("errormsg") + ")");
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }

        //同步sku下的商品
        syncSkuDetatilBySkuId(skuIds, categoryId);
    }

    /**
     * 根据skuId获取sku详情
     *
     * @param skuIds     skuIds集合
     * @param categoryId 对应分类
     */
    private void syncSkuDetatilBySkuId(List<String> skuIds, String categoryId) {
        if (CollectionUtils.isEmpty(skuIds)) {
            return;
        }

        //基本详情
        String url = colipuContextPath + colipuGetSkuDetailUrl;
        List<SkuDetailColDTO> detailColDTOS = new ArrayList<>();

        for (String skuId : skuIds) {
            String replaceUrl = url.replace("{sku}", skuId);
            Map<String, String> params = new HashMap<>(0);
            Map<String, String> headers = new HashMap<>(1);
            headers.put("Colipu-Token", iColipuTokenService.getToken());

            SkuDetailColDTO detailColDTO = new SkuDetailColDTO();
            try {
                String response = HttpClientExecutor.doGet(replaceUrl, params, headers);
                JSONObject jsonReturn = JSON.parseObject(response);
                if (jsonReturn.getBoolean("success")) {
                    String result = jsonReturn.getString("result");
                    detailColDTO = JSONObject.parseObject(result, SkuDetailColDTO.class);
                } else {
                    log.error("error:requestId(" + jsonReturn.getString("requestId")
                            + ");errorcode(" + jsonReturn.getString("errorcode")
                            + ");errormsg(" + jsonReturn.getString("errormsg") + ")");
                }
            } catch (Exception e) {
                log.error(e.getMessage());
            }

            detailColDTOS.add(detailColDTO);
        }

        //获取商品价格
        getSkuPrice(detailColDTOS);
        //商品基本信息和商品价格， 同步到中间表
        syncSkuThirdTable(detailColDTOS, categoryId);
    }

    /**
     * 获取商品价格接口
     *
     * @param detailColDTOS 对应的skuid
     */
    private void getSkuPrice(List<SkuDetailColDTO> detailColDTOS) {
        if (CollectionUtils.isEmpty(detailColDTOS)) {
            return;
        }

        //对应的skuid
        List<String> skuIdsPrice = CcUtils.collect(detailColDTOS, SkuDetailColDTO::getSku);
        int size = skuIdsPrice.size();
        //每次最多查询50个sku商品
        int times = size / 50;

        List<String> skuIdsStr;
        List<SkuPriceColDTO> listAll = new LinkedList<>();
        for (int i = 0; i <= times; i++) {
            if (i == times) {
                skuIdsStr = skuIdsPrice.subList(i * 50, size);
            } else {
                skuIdsStr = skuIdsPrice.subList(i * 50, (i + 1) * 50);
            }
            String skus = String.join(",", skuIdsStr);

            //调用商品价格Url
            String url = colipuContextPath + colipuGetSkuPriceUrl;
            Map<String, String> params = new HashMap<>(0);
            params.put("skus", skus);
            Map<String, String> headers = new HashMap<>(1);
            headers.put("Colipu-Token", iColipuTokenService.getToken());
            try {
                String response = HttpClientExecutor.doGet(url, params, headers);
                JSONObject jsonReturn = JSON.parseObject(response);
                if (jsonReturn.getBoolean("success")) {
                    String result = jsonReturn.getString("result");
                    List<SkuPriceColDTO> list = JSONObject.parseArray(result, SkuPriceColDTO.class);
                    listAll.addAll(list);
                } else {
                    log.error("error:requestId(" + jsonReturn.getString("requestId")
                            + ");errorcode(" + jsonReturn.getString("errorcode")
                            + ");errormsg(" + jsonReturn.getString("errormsg") + ")");
                }
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }
        //返回价格
        Map<String, SkuPriceColDTO> priceColDTOMap = CcUtils.toMap(listAll, SkuPriceColDTO::getSku);
        for (SkuDetailColDTO detailColDTO : detailColDTOS) {
            String sku = detailColDTO.getSku();
            SkuPriceColDTO skuPriceColDTO = priceColDTOMap.get(sku);
            BeanUtils.copyProperties(skuPriceColDTO, detailColDTO);
        }

    }

    /**
     * 同步到sku中间表
     *
     * @param skus       某个分类下所有sku详情(科力普最新)
     * @param categoryId 对应分类
     */
    private void syncSkuThirdTable(List<SkuDetailColDTO> skus, String categoryId) {
        if (CollectionUtils.isEmpty(skus)) {
            return;
        }

        //需要新增的商品sku
        List<CommerceColipuSkuDetail> addList = new LinkedList<>();
        //需要修改的商品sku
        List<CommerceColipuSkuDetail> updateList = new LinkedList<>();
        LocalDateTime now = LocalDateTime.now();

        QueryWrapper<CommerceColipuSkuDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("CategoryId", categoryId);
        List<CommerceColipuSkuDetail> skusExist = list(queryWrapper);
        if (CollectionUtils.isNotEmpty(skusExist)) {
            //全量的商品sku to Map
            Map<String, SkuDetailColDTO> skusMap = CcUtils.toMap(skus, SkuDetailColDTO::getSku);

            //判断已同步的商品是否需要修改
            skusExist.forEach(skuExist -> {
                String skuId = skuExist.getSkuId();
                SkuDetailColDTO sku = skusMap.get(skuId);
                if (null == sku) {
                    //删除
                    skuExist.setDeleteFlag(DeleteFlagEnum.IS_DELETE.getCode());
                    skuExist.setUpdateTime(now);
                    updateList.add(skuExist);

                } else {
                    //判断是否需要修改
                    CheckUpdateSkuCol checkUpdateSkuCol = checkUpdate(sku, skuExist);
                    if (checkUpdateSkuCol.getEUpdate()) {
                        updateList.add(checkUpdateSkuCol.getCommerceColipuSkuDetail());
                    }
                }

                //去除
                skus.remove(sku);
            });
        }

        //所有的新增的skuIds
        List<String> skuIds = CcUtils.collect(skus, SkuDetailColDTO::getSku);
        if (CollectionUtils.isNotEmpty(skuIds)) {
            //分类变更的逻辑判断
            QueryWrapper<CommerceColipuSkuDetail> queryWrapperBySkuId = new QueryWrapper<>();
            queryWrapper.in("SkuId", skuIds);
            List<CommerceColipuSkuDetail> skuDetails = list(queryWrapperBySkuId);
            //新增的商品sku to Map
            Map<String, CommerceColipuSkuDetail> skusMapAdd = CcUtils.toMap(skuDetails, CommerceColipuSkuDetail::getSkuId);

            //最后剩下的新增的
            skus.forEach(sku -> {
                CommerceColipuSkuDetail skuDetail;
                CommerceColipuSkuDetail skuDetailExist = skusMapAdd.get(sku.getSku());
                if (null != skuDetailExist) {
                    skuDetail = skuDetailExist;
                    skuDetail.setDeleteFlag(DeleteFlagEnum.NOT_DELETE.getCode());
                    skuDetail.setUpdateTime(now);
                    updateList.add(skuDetail);
                } else {
                    skuDetail = new CommerceColipuSkuDetail();
                    addList.add(skuDetail);
                }
                BeanUtils.copyProperties(sku, skuDetail);
                skuDetail.setSkuId(sku.getSku());
                skuDetail.setCategoryId(sku.getCategory());
                skuDetail.setImagePath(sku.getImage_path());
                skuDetail.setBrandName(sku.getBrand_name());
                skuDetail.setProductArea(sku.getProduct_area());
                skuDetail.setTaxRate(Double.valueOf(sku.getTax_rate()));
                skuDetail.setMallPrice(sku.getMall_price());
                skuDetail.setMarketPrice(sku.getMarket_price());
            });
        }

        if (CollectionUtils.isNotEmpty(addList)) {
            try {
                addList.forEach(this::save);
            }catch (Exception e){
                e.printStackTrace();
                log.error("科力普商品新增中间表出错！分类ID:" + categoryId);
            }
        }
        if (CollectionUtils.isNotEmpty(updateList)) {
            try {
                updateList.forEach(this::updateById);
            }catch (Exception e){
                e.printStackTrace();
                log.error("科力普商品修改中间表出错！");
            }
        }
    }

    /**
     * 判断是否需要修改
     *
     * @param sku      最新的商品详情（科力普）
     * @param skuExist 已存在的商品详情
     */
    private CheckUpdateSkuCol checkUpdate(SkuDetailColDTO sku, CommerceColipuSkuDetail skuExist) {
        CheckUpdateSkuCol updateSkuCol = new CheckUpdateSkuCol();
        //默认需要修改
        boolean isNeedUpdate = true;
        CommerceColipuSkuDetail skuDetailNew = new CommerceColipuSkuDetail();
        BeanUtils.copyProperties(sku, skuDetailNew);

        //名称不同的
        skuDetailNew.setImagePath(sku.getImage_path());
        skuDetailNew.setBrandName(sku.getBrand_name());
        skuDetailNew.setProductArea(sku.getProduct_area());
        skuDetailNew.setTaxRate(Double.valueOf(sku.getTax_rate()));
        skuDetailNew.setSkuId(sku.getSku());
        skuDetailNew.setCategoryId(sku.getCategory());
        skuDetailNew.setMallPrice(sku.getMall_price());
        skuDetailNew.setMarketPrice(sku.getMarket_price());

        skuDetailNew.setId(skuExist.getId());
        skuDetailNew.setCreateTime(skuExist.getCreateTime());
        skuDetailNew.setUpdateTime(skuExist.getUpdateTime());
        skuDetailNew.setDeleteFlag(skuExist.getDeleteFlag());
        if (skuDetailNew.equals(skuExist)) {
            isNeedUpdate = false;
        }

        updateSkuCol.setEUpdate(isNeedUpdate);
        updateSkuCol.setCommerceColipuSkuDetail(skuDetailNew);
        return updateSkuCol;
    }
}
